import numpy as np
import os
import pandas as pd
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
import random
from Job_Shop import Situation
import datetime
import time
from Instance_Generator import product_classdicts,product_crafts,Device_list,all_productins_types
import json


class DQN:
    def __init__(self,bom_dicts, J_num, order_data, Job_passtime_matrixs,Job_opnum_lst):
        self.bom_dicts = bom_dicts
        self.J_num = J_num
        self.order_data = order_data
        self.Job_passtime_matrixs = Job_passtime_matrixs
        self.Job_opnum_lst = Job_opnum_lst
        self.O_num = sum(Job_opnum_lst)

        self.product_classdicts = product_classdicts
        self.product_crafts  = product_crafts
        self.all_productins_types  = all_productins_types
        self.productins_nums  = len(all_productins_types)
        self.Device_list  = Device_list
        self.M_num  = len(Device_list)

        # self.today_str  = datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S')
        self.today_str  =  '2023-10-25 00:00:00'
        self.today_timestamp  = datetime.datetime.strptime(self.today_str, '%Y-%m-%d %H:%M:%S').timestamp()

    def main(self):
        self.Sit = Situation( self.bom_dicts, self.J_num, self.order_data, self.Job_passtime_matrixs,self.Job_opnum_lst)
        self.Sit.today_str = self.today_str
        self.Sit.today_timestamp = self.today_timestamp
        self.time_start = time.time()
        for i in range(self.O_num):
            at_trans = self.Sit.rule()
            self.Sit.scheduling(at_trans)
        self.time_end = time.time()
        print('求解耗时：', self.time_end - self.time_start)
        stats_info = {}

        product_class = {}
        for k in product_classdicts.keys():
            for v in product_classdicts[k]:
                product_class[v] = k
        ### 延迟率可视化
        tadiness = []
        max_tadiness = 0
        max_tadnums = 0
        for j in range(self.J_num):
            jiaofu_t = datetime.datetime.strptime(self.order_data[j]['交付日期'], '%Y-%m-%d %H:%M:%S').timestamp()-self.today_timestamp
            jiaofu_t = jiaofu_t/60
            tmp_tt = max(self.Sit.Jobs[j].End)
            tadiness.append(tmp_tt)
            if tmp_tt > max_tadiness:
                max_tadiness = tmp_tt
            if jiaofu_t >= tmp_tt:
                max_tadnums += 1
        avg_tad = sum(tadiness)/len(tadiness)

        print('<<<<<<<<<-----------------工单数:', self.J_num , '------------------->>>>>>>>>>')
        stats_info['工单数'] = self.J_num
        print('<<<<<<<<<-----------------机台数:', self.M_num, '------------------->>>>>>>>>>')
        stats_info['机台数'] = self.M_num
        print('<<<<<<<<<-----------------准时交付率:',max_tadnums/ self.J_num, '------------------->>>>>>>>>>')
        stats_info['准时交付率'] = max_tadnums/ self.J_num
        print('<<<<<<<<<-----------------工单平均交付天数:',avg_tad/(60*24), '------------------->>>>>>>>>>')
        stats_info['工单平均交付天数'] = avg_tad/(60*24)
        print('<<<<<<<<<-----------------工单最大交付天数:', max_tadiness/(60*24), '------------------->>>>>>>>>>')
        stats_info['工单最大交付天数'] = max_tadiness/(60*24)

        day_num = int(max_tadiness//(24*60)+1)
        Switching_no = 0
        all_lst = []
        for mm in range(self.M_num):
            Machines = self.Sit.Machines[mm]
            work_center = self.Device_list[mm]
            for dd in range(day_num):
                floor = dd*24*60
                upper = (dd+1)*24*60
                for xx in range(len(Machines.Start)):
                    jid = Machines.assign_for[xx]
                    order_info = self.order_data[jid[0]]

                    order_no = order_info['订单编号']
                    cp,ms,xh,gg = eval(order_info['产品名称'])
                    amount = int(order_info['数量'])
                    deliver_date = order_info['交付日期']
                    ops_str = product_crafts[product_class[xh]][jid[1]]

                    if  Machines.Start[xx] <= floor and floor < Machines.End[xx] < upper:
                        p_time = Machines.End[xx] - floor
                        p_time = round(p_time,2)
                        start_tt = 0
                        end_tt = p_time
                        all_lst.append([work_center,dd,order_no,cp,ms,xh,gg,amount,ops_str, deliver_date, p_time,start_tt,end_tt])
                    elif floor < Machines.Start[xx] < upper and floor < Machines.End[xx] < upper:
                        p_time = Machines.End[xx] - Machines.Start[xx]
                        p_time = round(p_time,2)
                        start_tt = Machines.Start[xx] - floor
                        end_tt =  start_tt + p_time
                        all_lst.append([work_center,dd,order_no,cp,ms,xh,gg,amount,ops_str, deliver_date, p_time,start_tt,end_tt])
                    elif floor < Machines.Start[xx] < upper and upper <= Machines.End[xx]:
                        p_time = upper - Machines.Start[xx]
                        p_time = round(p_time,2)
                        start_tt = Machines.Start[xx] - floor
                        end_tt =  24*60
                        all_lst.append([work_center,dd,order_no,cp,ms,xh,gg,amount,ops_str, deliver_date, p_time,start_tt,end_tt])
            for xx in range(len(Machines.Start_Switch)):
                Switching_no += 1
                dhx = int(Machines.Start_Switch[xx]//(24*60))
                p_time =  Machines.T_Switch[xx]
                p_time = round(p_time, 2)
                start_tt = Machines.Start_Switch[xx] - dhx * (24*60)
                end_tt = Machines.End_Switch[xx] - dhx * (24*60)
                all_lst.append([work_center, dhx, '换型'+str(Switching_no), '', '', '', '', '', Machines.assign_Switch[xx], '', p_time,start_tt,end_tt])

        print('<<<<<<<<<-----------------总换型次数:',Switching_no, '------------------->>>>>>>>>>')
        stats_info['总换型次数'] = Switching_no
        print('<<<<<<<<<-----------------机台平均换型次数:',Switching_no/self.M_num, '------------------->>>>>>>>>>')
        stats_info['机台平均换型次数'] = Switching_no/self.M_num
        detail_data = pd.DataFrame(all_lst,columns=['机台','日期','工单号','产品','描述','型号','规格','数量','工序','交付日期', '工时', '开始时刻', '结束时刻'])
        detail_data_lst = []
        for i in range(len(detail_data)):
            tmp_dict = {}
            tmp_data = detail_data.iloc[i]
            for ind in tmp_data.index:
                tmp_dict[ind] = str(tmp_data[ind])
            detail_data_lst.append(tmp_dict)
        ############################################################################################################
        temp_lst = []
        for name, group in detail_data.groupby(['机台','日期']):
            work_times = group.工时.sum()
            work_times = (24 * 60) if work_times > (24 * 60) else work_times
            rate = round(work_times / (24 * 60),2)
            temp_lst.append([name[0],name[1],24*60, work_times,rate])
        whole_data = pd.DataFrame(temp_lst,columns=['机台','日期','产能','负荷','负荷率'] )
        whole_data.to_excel('./out/负荷计划.xlsx', index=False)
        print('<<<<<<<<<-----------------平均负荷率:',whole_data.负荷率.mean(), '------------------->>>>>>>>>>')
        stats_info['平均负荷率'] = whole_data.负荷率.mean()
        whole_data_lst = []
        for i in range(len(whole_data)):
            tmp_dict = {}
            tmp_data = whole_data.iloc[i]
            for ind in tmp_data.index:
                tmp_dict[ind] = str(tmp_data[ind])
            whole_data_lst.append(tmp_dict)
        ############################################################################################################
        detail_data01 = detail_data[detail_data.工单号.map(lambda x: '换型' not in x)]
        detail_data01['原工单号'] = detail_data01['工单号'].map(lambda x:  str(x).split('-')[0])
        temp_lst = []
        for name, group in detail_data01.groupby('原工单号'):
            group['结束时间'] = group['日期']*24*60 + group['结束时刻']
            deliver_date =  group.结束时间.max()
            temp_lst.append([name, deliver_date])
        deliver_data = pd.DataFrame(temp_lst, columns=[ '工单号','完成时间'])
        order_df = pd.read_excel('./data/工单明细.xlsx')
        deliver_data01 = pd.merge(order_df, deliver_data, how='inner', on=['工单号'])
        deliver_data01.to_excel('./out/工单完成日期表.xlsx', index=False)
        deliver_lst = []
        for i in range(len(deliver_data01)):
            tmp_dict = {}
            tmp_data = deliver_data01.iloc[i]
            for ind in tmp_data.index:
                tmp_dict[ind] = str(tmp_data[ind])
            deliver_lst.append(tmp_dict)
        ############################################################################################################
        temp_lst = []
        for name, group in detail_data01.groupby('工单号'):
            proc_startdate =  group.日期.min()
            product_xhgg = group.型号.iloc[0] + '_' + group.规格.iloc[0].split('×')[-1]
            bomdata = self.bom_dicts[product_xhgg]
            amount = group.数量.iloc[0]
            temp_lst.append([name, proc_startdate,bomdata['铜原料']*amount,bomdata['绝缘料']*amount,bomdata['云母带']*amount])
        wuliao_data = pd.DataFrame(temp_lst, columns=['工单号','日期', '铜原料', '绝缘料', '云母带'])
        temp_lst = []
        for name, group in wuliao_data.groupby('日期'):
            temp_lst.append([name,group.铜原料.sum(),group.绝缘料.sum(),group.云母带.sum()])
        wuliao_data =  pd.DataFrame(temp_lst, columns=['日期', '铜原料', '绝缘料', '云母带'])
        wuliao_data.to_excel('./out/用料计划.xlsx', index=False)
        wuliao_data_lst = []
        for i in range(len(wuliao_data)):
            tmp_dict = {}
            tmp_data = wuliao_data.iloc[i]
            for ind in tmp_data.index:
                tmp_dict[ind] = str(tmp_data[ind])
            wuliao_data_lst.append(tmp_dict)

        ################################################ 时间转换 #######################################################################
        detail_data_lst01 = []
        for dd in detail_data_lst:
            dd_timestamp = self.today_timestamp + int(dd['日期'])*24*60*60
            dd['日期'] = datetime.datetime.fromtimestamp(dd_timestamp).strftime('%Y-%m-%d %H:%M:%S')[:10]
            dd['开始时刻'] = datetime.datetime.fromtimestamp(dd_timestamp + float(dd['开始时刻'])*60).strftime('%Y-%m-%d %H:%M:%S')
            dd['结束时刻'] = datetime.datetime.fromtimestamp(dd_timestamp + float(dd['结束时刻'])*60).strftime('%Y-%m-%d %H:%M:%S')
            hour_num = int(float(dd['工时']) // 60)
            hour_str = str(hour_num).rjust(2, '0')
            minute_num = int(float(dd['工时']) % 60)
            minute_str = str(minute_num).rjust(2, '0')
            decimal_part = int((float(dd['工时']) % 1)*60)
            seconds_str = str(decimal_part).rjust(2, '0')
            dd['工时'] = hour_str+':'+minute_str+':'+seconds_str
            detail_data_lst01.append(dd)

        detail_data_lst02 = []
        for dd in detail_data_lst01:
            tmp = []
            for col in ['机台', '日期', '工单号', '产品', '描述', '型号', '规格', '数量', '工序', '交付日期', '工时', '开始时刻', '结束时刻']:
                tmp.append(dd[col])
            detail_data_lst02.append(tmp)
        detail_data = pd.DataFrame(detail_data_lst02, columns=['机台', '日期', '工单号', '产品', '描述', '型号', '规格', '数量', '工序', '交付日期', '工时', '开始时刻', '结束时刻'])
        detail_data = detail_data.sort_values(['机台','日期','开始时刻'])
        detail_data.to_excel('./out/详细计划.xlsx', index=False)

        whole_data_lst01 = []
        for dd in whole_data_lst:
            dd['日期'] = datetime.datetime.fromtimestamp(self.today_timestamp + int(dd['日期'])*24*60*60).strftime('%Y-%m-%d')
            dd['产能'] = 24
            dd['负荷'] = round(float(dd['负荷'])/60,2)
            whole_data_lst01.append(dd)

        deliver_lst01 = []
        for dd in deliver_lst:
            dd['完成时间'] = datetime.datetime.fromtimestamp(self.today_timestamp + float(dd['完成时间'])*60).strftime('%Y-%m-%d %H:%M:%S')
            deliver_lst01.append(dd)

        wuliao_data_lst01 = []
        for dd in wuliao_data_lst:
            dd['日期'] = datetime.datetime.fromtimestamp(self.today_timestamp + float(dd['日期'])*24*60*60).strftime('%Y-%m-%d')
            wuliao_data_lst01.append(dd)
        out = {'详细计划': detail_data_lst01,'负荷计划': whole_data_lst01, '工单完成日期表': deliver_lst01, '用料计划': wuliao_data_lst01}
        for ky in stats_info.keys():
            out[ky] = stats_info[ky]
        return out





